﻿#pragma once


#include <atomic>
#include <mutex>
#include "Containers/Vector.h"
#include "Containers/Delegate.h"
#include "Containers/String.h"
#include "Containers/String8.h"
#include "Containers/ThreadSafePtr.h"
#include "IPAddress.h"

class CSocketPlatformData;

enum class ETCPClientState
{
    Idle,  //空闲状态 
    Connected, //已连接到服务器
};

enum class ETCPClientError
{
    CreateSocketError, //创建socket失败
    ConnectError, //连接失败
    ConnectTwiceError, //重复连接,当前socket已经连接到服务器,不能再次连接
    ConnectInterruptedError, //连接意外中断
};

//由于底层使用到了线程安全的智能指针，
//所以这个类对像也得使用线程安全的智能指针
class WHENGINE_API CTCPClient : public EnableThreadSafeSharedPtrFromThis<CTCPClient>
{
protected:
    CTCPClient();
    CTCPClient(CSocketPlatformData*  InConnectedSocket);
public:
    static TThreadSafeSharedPtr<CTCPClient> Create();

    ~CTCPClient();

    //连接到指定的IP和端口
    void Connect(const SIPAddress& IP, uint16_t Port);

    // //当前线程等待直到连接成功
    // void WaitForConnected();
    // //当连接成功时由工作线程触发
    // TDelegate<void> OnConnected;

    //主动断开连接
    void Disconnect();
    //当连接断开时由工作线程触发
    TDelegate<void> OnDisconnected;

    bool IsConnected();

    //读取所有收到的数据
    TVector<uint8_t> ReadAllData();
    //当有新的数据到达时由工作线程触发
    TDelegate<void> OnDataReceived;
    //当前线程等待直到有新的数据到达
    void WaitForDataReceived();

    //only supoort utf8 string
    static CString8 ConvertDataToString8(const TVector<uint8_t>& InData);
    //only supoort utf8 string
    static CString ConvertDataToString(const TVector<uint8_t>& InData);

    //发送数据
    void Send(const TVector<uint8_t>& InMessage);
    //发送Utf32字符串，内部会转换为Utf8
    void Send(const CString& InMessage);
    void Send(const CString8& InMessage);
    //当前线程等待直到所有数据发送完成
    void WaitForDataSent();

    //socket错误事件,当发生错误时触发,可能由主线程或者工作线程触发
    TDelegate<void, ETCPClientError> OnErrorOccured;
protected:
    std::mutex SocketMutex;
    CSocketPlatformData* PlatformData= nullptr;
    ETCPClientState State=ETCPClientState::Idle;
    void PostConnected();
    friend class CTCPServer;

    std::mutex ReceivedDataMutex;
    TVector<uint8_t> ReceivedData;
    //接收数据并检查连接是否断开
    void StartReceiveAndDetectTask();
    std::atomic<int32_t> ReceiveBufferSize=1024;

    std::mutex SendDataMutex;
    TVector<uint8_t> SendData;
    //发送数据,不能用于检测连接是否断开
    //因为没有数据发送时，这个任务不会真的执行发送
    void StartSendTask();

    //用一个已经连接的socket初始化
    void InitWith(CSocketPlatformData*  InConnectedSocket);

};
